import wkt from "wkt";
import * as turf from '@turf/turf'
import { drawPolygonByGeojson } from '@/utils/map'

export default {
  data () {
    return {
      logicData: null,
      popupData: null
    }
  },
  methods: {
    /**
     * 确认开启逻辑单体化的函数
     *
     * @param data 逻辑单体化数据
     * @returns 无返回值
     */
    logicConfirm (data) {
      this.logicData = data
      this.showLogicDialog = false
      // 创建一个ScreenSpaceEventHandler实例来处理鼠标事件
      this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
      // 注册左键单击事件
      this.handler.setInputAction(this.getLeftClickPosition, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    },
    /**
     * 获取鼠标左键点击位置的地图数据
     *
     * @param click 鼠标点击事件对象
     * @returns 无返回值，会调用相关函数处理点击事件
     */
    async getLeftClickPosition (click) {
      this.removeMaskAndFrame()
      let cartesian = null;
      // 获取鼠标点击的屏幕坐标
      const pickedObject = this.viewer.scene.pick(click.position);
      if (pickedObject && pickedObject.primitive && pickedObject.primitive.attribute && pickedObject.primitive.attribute.resourceId) {
        cartesian = this.viewer.scene.pickPosition(click.position);
        console.log(cartesian,'逻辑单体化');
        if (!cartesian) {
          this.$message.error('获取坐标点失败')
          return
        }
        const resourceId = pickedObject.primitive.attribute.resourceId
        if (this.logicData.tileInfo.attribute.resourceId === resourceId) {
          const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
          const lon = Cesium.Math.toDegrees(cartographic.longitude);
          const lat = Cesium.Math.toDegrees(cartographic.latitude);
          const height = cartographic.height;
          console.log({lon,lat,height},'逻辑单体化经纬度');
          try {
            const maskingData = await this.getVectorData({ lon, lat, height });
            if (maskingData && maskingData.data && maskingData.data.length > 0) {
              const { data, spatialField } = maskingData
              this.renderMask(data[0], spatialField);
              this.popupData = { ...data[0] }
              delete this.popupData[spatialField]
              delete this.popupData['@geom']
              this.addMaskPopup(data[0], cartesian)
            } else {
              this.$message.error('没有获取到有效的矢量数据');
            }
          } catch (error) {
            this.$message.error('在获取矢量数据时发生错误: ' + error.message);
          }
        }
      }
    },
    /**
     * 渲染遮罩
     *
     * @param data 渲染遮罩所需数据
     * @param spatialField 空间字段
     * @returns 无返回值
     * @throws 当WKT解析失败时，抛出错误
     * @throws 当地理数据缓冲失败时，抛出错误
     */
    renderMask (data, spatialField) {
      try {
        const { color, opacity } = this.logicData
        const geom = data[spatialField] ? data[spatialField] : data['@geom']
        const geojson = wkt.parse(geom);
        if (!geojson) {
          throw new Error('WKT解析失败');
        }
        const buffered = turf.buffer(geojson, 0.005, { units: 'kilometers' });
        if (!buffered) {
          throw new Error('地理数据缓冲失败');
        }
        this.maskingPrimitives = drawPolygonByGeojson(this.viewer, buffered, color, opacity)
      } catch (error) {
        // 统一处理渲染遮罩和详情弹窗时可能出现的异常
        this.$message.error('渲染遮罩时发生错误: ' + error.message);
      }
    },

    /**
     * 添加建筑详情popup
     *
     * @param data 数据对象
     * @param cartesian 笛卡尔坐标
     * @returns 无返回值
     */
    addMaskPopup (data, cartesian) {
      if (!data) {
        return
      }
      let element = this.$refs.logicPopup.$el;
      let option = {
        element: element,
        position: cartesian,
        offset: {
          x: 0, // 向屏幕左边平移的像素值
          y: 0 // 向屏幕下方平移的像素值
        }
      };
      try {
        // 尝试创建并添加Overlay，如果出现异常则捕获并处理
        this.currOverlay = new Cesium.Overlay(option);
        this.viewer.addOverlay(this.currOverlay);
        this.currOverlay.show();
      } catch (error) {
        // 统一处理Overlay创建或显示时可能出现的异常
        this.$message.error('添加建筑详情弹窗时发生错误: ' + error.message);
      }
    },

    // 移除遮罩层和详情弹窗
    removeMaskAndFrame () {
      if (this.maskingPrimitives.length > 0) {
        this.maskingPrimitives.forEach(item => {
          this.viewer.scene.primitives.remove(item)
        })
        this.maskingPrimitives = []
      }
      this.currOverlay && this.currOverlay.destroy();
      this.currOverlay = null
    },
    /**
     * 获取当前点矢量信息和遮罩wkt
     *
     * @param {Object} coordinate - 坐标信息
     * @returns {Promise<Object>} - 矢量数据
     */
    async getVectorData (coordinate) {
      const { serverType, serverUrl, serverIpPort } = this.logicData.vectorInfo.attribute;
      let queryData = null
      const level = this.viewer.scene.globe._surface._tilesToRender[0]._level;
      const params = { ...coordinate, serverUrl, serverIpPort, serverType, level }
      try {
        if (['WMTS', 'WMS'].includes(serverType)) {
          queryData = await this.getQueryData(params);
        } else if (serverType === 'XYZ') {
          queryData = await this.getXYZQueryData(params);
        }
      } catch (error) {
        this.$message.error('在获取矢量数据时发生错误: ' + error.message);
        return;
      }


      return queryData;
    },

    /**
     * 异步从XYZ服务中获取矢量数据
     *
     * @param params 查询参数对象
     * @param params.serverUrl 服务器地址
     * @returns 查询结果数据
     */
    async getXYZQueryData (params) {
      const { serverUrl } = params
      const serverInfo = this.analysisByUrl(serverUrl);
      const queryData = await this.getServerInfo({ ...serverInfo, ...params });
      return queryData;
    },

    /**
     * 根据URL进行分析
     *
     * @param serverUrl 服务器URL
     * @returns 包含styleName和serverName的对象
     */
    analysisByUrl (serverUrl) {
      const styleName = this.getParamFromUrl(serverUrl, 'styleId')
      const urlSplit = serverUrl.split('/')
      const serverName = urlSplit[urlSplit.length - 2]
      return {
        styleName,
        serverName
      }
    },

    /**
     * 从URL中获取指定参数的值
     *
     * @param url URL地址
     * @param paramName 参数名称
     * @returns 返回指定参数的值，若不存在则返回null
     */
    getParamFromUrl (url, paramName) {
      // 创建一个URL对象
      const urlObj = new URL(url);

      // 获取查询参数部分，并创建一个URLSearchParams对象
      const searchParams = new URLSearchParams(urlObj.search);

      // 返回指定参数的值
      return searchParams.get(paramName);
    },
    /**
     * 获取WMTS服务的矢量数据
     *
     * @param {Object} coordinate - 坐标信息
     * @param {string} serverUrl - 服务的URL
     * @param {string} serverIpPort - 服务的IP和端口
     * @param {string} serverType - 服务的类型
     * @returns {Promise<Object>} - 矢量数据
     */
    async getQueryData (params) {
      const { serverUrl, serverType } = params
      const serverInfo = await this.getCapabilities(serverUrl, serverType);
      const queryData = await this.getServerInfo({ ...serverInfo, ...params });
      return queryData;
    },

    /**
     * 从pickup中获取服务信息，从query中获取空间信息
     *
     * @param params 参数对象
     * @param params.serverIpPort 服务器IP地址和端口
     * @param params.serverName 服务名称
     * @param params.styleName 样式名称
     * @param params.lon 经度
     * @param params.lat 纬度
     * @param params.level 层级
     * @returns 查询结果
     */
    async getServerInfo (params) {
      const { serverIpPort, serverName, styleName, lon, lat, level } = params
      const pickUrl = `${serverIpPort}/mapserver/${serverName}/${styleName}/pickup?lon=${lon}&lat=${lat}&level=${level}`;
      const pickupData = await this.$get(pickUrl);
      const layers = Object.keys(pickupData);

      if (layers.length === 0) {
        this.$message.error('没有获取到数据');
        return;
      } else if (layers.length > 1) {
        this.$message.error('矢量数据需要是单数据服务');
        return;
      }

      const layer = layers[0];
      const spatialField = await this.findSpatialFields(serverIpPort, serverName, layer);
      const queryUrl = `${serverIpPort}/mapserver/${serverName}/${layer}/query?spatialFilter=POINT(${lon} ${lat})&withGeometry=true&withAllFields=true`;
      const queryData = await this.$get(queryUrl);

      return { data: queryData, spatialField };
    },

    async findSpatialFields (serverIpPort, serverName, layer) {
      const url = `${serverIpPort}/mapserver/serverInfo/${serverName}.json`
      const response = await this.$get(url)
      const { spatialField } = response.layerMap[layer]
      return spatialField
    },

    /**
     * 从服务xml中获取信息
     *
     * @param serverUrl 服务URL
     * @param serverType 服务类型（WMTS或WMS）
     * @returns 服务信息
     */
    async getCapabilities (serverUrl, serverType) {
      const capabilitiesUrl = `${serverUrl.split(serverType === 'WMTS' ? 'getTile' : 'getMap')[0]}getCapabilities`;
      const xmlResponse = await this.$get(capabilitiesUrl);
      const xmlDom = new DOMParser().parseFromString(xmlResponse, 'text/xml');
      let serverInfo = null;
      switch (serverType) {
        case 'WMTS':
          serverInfo = this.getServerFromWMTS(xmlDom)
          break;
        case 'WMS':
          serverInfo = this.getServerFromWMS(xmlDom)
        default:
          break;
      }
      return serverInfo;
    },

    /**
     * 从WMTS服务中获取信息
     *
     * @param xml WMTS的XML信息
     * @returns 返回服务器名称和样式名称的对象，如果获取失败则返回null
     */
    getServerFromWMTS (xml) {
      try {
        const serverIdentification = xml.getElementsByTagNameNS("http://www.opengis.net/ows/1.1", "ServiceIdentification")[0];
        if (!serverIdentification) {
          throw new Error('Server Identification element not found');
        }
        const serverName = serverIdentification.getElementsByTagNameNS("http://www.opengis.net/ows/1.1", "Title")[0].textContent;

        const styles = xml.getElementsByTagName("Style");
        if (!styles.length) {
          throw new Error('No Style elements found');
        }
        const style = styles[0];
        const styleName = style.getElementsByTagNameNS("http://www.opengis.net/ows/1.1", "Identifier")[0].textContent;

        return { serverName, styleName };
      } catch (error) {
        this.$message.error('获取服务信息失败: ' + error.message);
        return null;
      }
    },

    /**
     * 从WMS服务中获取信息
     *
     * @param xml WMS的XML数据
     * @returns 返回一个包含服务器名称和样式名称的对象，如果获取失败则返回null
     */
    getServerFromWMS (xml) {
      try {
        const serverIdentification = xml.getElementsByTagName("Service")[0];
        if (!serverIdentification) {
          throw new Error('Server Identification element not found');
        }
        const serverName = serverIdentification.getElementsByTagName("Name")[0].textContent;

        const styles = xml.getElementsByTagName("Style");
        if (!styles.length) {
          throw new Error('No Style elements found');
        }
        const style = styles[0];
        const styleName = style.getElementsByTagName("Title")[0].textContent;

        return { serverName, styleName };
      } catch (error) {
        this.$message.error('获取服务信息失败: ' + error.message);
        return null;
      }
    },

    // 关闭逻辑单体化
    closeLogic () {
      this.isOpenLogic = false
      this.showLogicDialog = false
    }
  },
  created () {
    this.maskingPrimitives = []
    this.currOverlay = null
  }
}